package source;

import java.util.*;
import source.view.*;

/**
 * Container class for Units. It is represented as a subclass of Unit to allow
 * the Army to replace the Units that are incorporated inside it.
 * @author Sean Larson
 *
 */
public class Army extends Unit {

	private int numOfUnits = 0;
	
	private Vector<Unit> units;
	
	/**
	 * Creates an Army out of the array of Units sent to the constructor.
	 * @param units - array of Units that creates the Army
	 */
	public Army(Unit[] unitarray, PlayerStatus player, Tile position) {
		super(UnitType.ARMY, player, position);
		units = new Vector<Unit>();
		for (Unit u : unitarray) {
			if (u!=(null)) { 
				if (u.getUnitType() == UnitType.ARMY) {
					Army uArmy = (Army)u;
					Unit[] toAdd = uArmy.getUnits();
					uArmy.destroy();
					for (Unit oldArmyUnit : toAdd) {
						this.addUnit(oldArmyUnit);
					}
				}
				else {
					this.addUnit(u);		
				}
			}
		}
		this.determineMvRate();
		this.determineViewDist();
		this.determineAttackPower();
		this.determineDefensivePower();
		this.determineCurrentHP();
		this.determineMaxHP();
		player.addUnit(this);
		position.addUnit(this);
		MainScreen.writeToConsole("Army: Army created.");
	}
	
	public int size() {
		return this.numOfUnits;
	}
	
	public Unit[] getUnits() {
		Unit[] us = new Unit[this.numOfUnits];
		int index = 0;
		for (Unit u : this.units) {
			us[index++] = u;
		}
		return us;
	}
	
	/**
	 * Returns the total upkeep of the Units in the army
	 * @return Upkeep, int, upkeep in energy units
	 */
	public int getUpkeep(){
		int upkeep = 0;
		for (Unit u : units){
			upkeep += u.getUpkeep();
		}
		return upkeep;
	}
	
	/**
	 * Add a unit to this army
	 * @param unit - the Unit to add
	 */
	public void addUnit(Unit unit) {
		unit.setPosition(null);		// this is done so that the units in Army
									// do not think they are still on the Tile
									// the Army was created on
		getPlayer().removeUnit(unit);
		getPlayer().modifyEnergyUsed(unit.getUnitType().upkeep());
		getPosition().removeUnit(unit);
		this.units.add(unit);
		this.numOfUnits++;
		//MainScreen.writeToConsole("Army: Unit added to Army.");
	}
	
	/**
	 * Add an array of Units to this army
	 * @param units - an array of Units to add
	 */
	public void addUnits(Unit[] units) {
		for (Unit u : units) {
			if (!u.equals(null)) {
				u.setPosition(null);
				this.units.add(u);
			}
		}
		MainScreen.writeToConsole("Army: Units added to Army.");
	}
	
	/**
	 * Seperates this Army into each individual Unit.
	 * Must inform the Tile and PlayerStatus of the Units being released
	 *
	 */
	public void breakArmy() {
		for (Unit u : this.units) {
			this.getPosition().addUnit(u);
			u.setPosition(this.getPosition());
			this.getPlayer().addUnit(u);
			this.getPlayer().modifyEnergyUsed(-u.getUnitType().upkeep());
		}
		this.getPosition().removeUnit(this);
		this.getPlayer().removeUnit(this);
		this.destroy();
		MainScreen.writeToConsole("Army: Army has been broken up.");
	}
	
	/**
	 * Cycles through all Units inside the Army and determines the Unit with the
	 * lowest movement rate and sets that as the movement rate of the Army.
	 *
	 */
	private void determineMvRate() {
		this.setMovementRate(this.units.get(0).getMovementRate());
		for (Unit u : units) {
			if (this.getMovementRate() > u.getMovementRate()) {
				this.setMovementRate(u.getMovementRate());
			}
		}
	}
	
	/**
	 * Cycles through all Units inside the Army and determines the Unit with the
	 * highest view distance and sets that as the view distance of the Army.
	 *
	 */
	private void determineViewDist() {
		this.setViewDistance(0);
		for (Unit u : this.units) {
			if (this.getViewDistance() < u.getViewDistance()) {
				this.setViewDistance(u.getViewDistance());
			}
		}
	}	
	
	private void determineAttackPower(){
		int sum = 0;
		for(Unit u : this.units){
			sum += u.getAttackPower();
		}

		this.setAttackPower(sum);
	}

	private void determineDefensivePower(){
		int sum = 0;
		for(Unit u : this.units){
			sum += u.getDefensivePower();
		}
		MainScreen.writeToConsole("Determined def power to be " + sum);
	
		this.setDefensivePower(sum);
	}

	private void determineCurrentHP(){
		int sum = 0;
		for(Unit u : this.units){
			sum += u.getCurrentHP();
		}
		
		this.setCurrentHP(sum);
	}

	private void determineMaxHP(){
		int sum = 0;
		for(Unit u : this.units){
			sum += u.getMaxHP();
		}

		this.setMaxHP(sum);
	}

	public boolean destroy() {		
		for (int i = 0; i < this.units.size(); i++) {
			this.units.remove(i);
		}
		return super.destroy();
	}
}
